Skip to content

feat(hook): one-click clear-context + bypass via native plan-accept + keystroke injection#693

Open
AgileInnov8tor wants to merge 35 commits into
backnotprop:mainfrom
AgileInnov8tor:main
Open

feat(hook): one-click clear-context + bypass via native plan-accept + keystroke injection#693
AgileInnov8tor wants to merge 35 commits into
backnotprop:mainfrom
AgileInnov8tor:main

Conversation

@AgileInnov8tor
Copy link
Copy Markdown
Contributor

@AgileInnov8tor AgileInnov8tor commented May 11, 2026

Summary

Proper replacement for the reverted PR #668 (Expose bypass clear reminder permission mode).

PR #668 was reverted because the hook emitted a /clear reminder that was never actually displayed — a silent no-op. This PR takes a different approach: instead of trying to do the impossible (hooks cannot clear context directly), it defers to Claude Code's own native primitive.

What changed

Four commits:

  1. Wire truthful approval semantics (9096eff, c7727b9) — thread permissionMode and a new deferToNativeForClear flag through the decision pipeline so the hook knows when to defer vs. when to nudge.

  2. Consent-gated native deferral (ff79946) — when user picks "Approve + Bypass + Clear Context (native)":

    • Hook writes showClearContextOnPlanAccept: true to ~/.claude/settings.json (consent-gated, atomic write with retry)
    • Hook exits 0 with empty stdout (native passthrough)
    • Claude Code's built-in plan-accept dialog appears and shows "Yes, clear context and bypass permissions" (because the setting is now on)
  3. Keystroke injection for one-click UX (12cddf7, apps/hook/server/keystrokeInjector.ts) — before exiting 0, spawn a detached background process that fires "1\n" into the CC terminal after 600ms:

    • tmux ($TMUX_PANE): tmux send-keys -t <pane> 1 Enter (no accessibility permissions needed)
    • macOS non-tmux: osascript iterating {warp, iTerm2, Terminal} via System Events
    • Linux/Windows without tmux: no-op (user sees native dialog, presses 1 manually)
    • Silent-fail: accessibility denied or terminal not found → falls back to manual press, no crash
  4. Slop cleanup (fb6c44d) — no behavior change; removes AI-generated bloat from keystrokeInjector:

    • keystrokeInjector.ts 78→39 lines: delete 16-line module docblock + 5-line JSDoc; inline two single-use builder functions; unify the duplicated Bun.spawn+.unref() into a single call
    • keystrokeInjector.test.ts 118→107 lines: extract setPlatform(v) helper replacing 5× repeated Object.defineProperty blocks

Why not a hook clearContext field?

CC's updatedPermissions types are addRules/setMode/removeRules. There is no clearContext entry (verified by exhaustive string scan of the CC 2.1.138 binary). The plan-accept TUI dialog is hardcoded in CC's React renderer and cannot be bypassed from a hook. The native passthrough + keystroke injection is the only viable path that preserves true context-clearing without patching CC.

User experience

Before: Review plan in plannotator → click → still have to press "1" in terminal

After: Review plan in plannotator → click "Approve + Bypass + Clear Context (native)" → context cleared, bypass mode set, plan executes — zero additional keystrokes

Test plan

  • bun test packages/server packages/editor apps/hook — 265/265 pass
  • bun run build:hook — clean build
  • Manual smoke test on WarpTerminal (macOS): ExitPlanMode → plannotator UI → click entry → CC terminal auto-selects option 1 → plan executes
  • Headless probes (5 scenarios): with-consent, no-consent, already-enabled, no-settings, malformed-settings — all pass

Notes

  • Consent for the settings mutation lives at ~/.plannotator/consent/clear-context-setting.json
  • The showClearContextOnPlanAccept setting defaults to false in CC (changelog: "hidden by default in plan mode"); this PR turns it on consent-gated, not globally
  • Keystroke delay (600ms) is configurable in code; conservative enough for CC dialog render time (~200–500ms)

🤖 Generated with Claude Code

@backnotprop
Copy link
Copy Markdown
Owner

Before: Review plan in plannotator → click → still have to press "1" in terminal

Can you explain what do you mean by this? 'Cause right now it's all automated. You just approve and the agent goes on.

@AgileInnov8tor
Copy link
Copy Markdown
Contributor Author

The "before" is specific to the "Approve + Bypass + Clear Context (native)" option, not the standard approve flow which is already zero keystrokes.

Background: showClearContextOnPlanAccept: true must be set in ~/.claude/settings.json for the native dialog to appear. The hook writes this on first use (consent gated). Once set, CC waits for the user to press 1 in the terminal. This PR automates that keypress via tmux/osascript.

@backnotprop
Copy link
Copy Markdown
Owner

Okay, I think I understand. So this would require the user to turn that on and then Instead of auto approving the plan, it just pauses and then the user gets the option to clear context.

@AgileInnov8tor
Copy link
Copy Markdown
Contributor Author

AgileInnov8tor commented May 13, 2026 via email

AgileInnov8tor and others added 26 commits May 14, 2026 16:06
Thread a clear-context reminder flag through approval decisions, expose a Claude Code-only approval entry that requests bypass mode, and keep the hook response honest by emitting a reminder instead of claiming context was cleared.

Constraint: Claude Code PermissionRequest hooks have no documented clearContext response field and bypassPermissions is only a request when the mode is available.

Rejected: adding a permission-mode enum or undocumented clearContext field | those would misrepresent hook capabilities and broaden the contract.

Confidence: high

Scope-risk: moderate

Directive: Do not claim Plannotator clears context until Claude Code documents a hook field for that behavior; keep reminder copy truthful.

Tested: bun test packages/server apps/hook; bun test packages/editor/wideMode.test.ts packages/ui/hooks/useAgentSettings.test.ts; bun test; bun run build:review; bun run build:hook; bun run typecheck; git diff --check --cached.

Not-tested: Browser warning-dialog replay and interactive Claude Code smoke test.

Co-authored-by: OmX <omx@oh-my-codex.dev>
Constraint: Claude Code hooks cannot clear context directly; the new action remains a truthful reminder plus bypass-mode approval.
Rejected: Sending OpenCode agent-switch state for Claude Code | it leaked build (?) UI state and misleading payload fields.
Confidence: high
Scope-risk: narrow
Directive: Keep OpenCode agent switching gated to opencode-origin approval payloads.
Tested: bun run typecheck; bun test; bun run build:review; bun run build:hook
Not-tested: Manual browser click-through of the Claude Code dropdown.
Route Claude Code plan approvals through explicit bypass payloads, consent-gated native clear-context deferral, and a fallback /clear nudge so selecting the clear-context mode no longer collapses into a silent approval no-op. The active ignored hook bundle was rebuilt locally after this source change.

Constraint: Claude Code hooks cannot directly clear context; native clear requires showClearContextOnPlanAccept and user consent.\nRejected: Treating bypassPermissionsClearReminder as a raw permissionMode | Claude Code only accepts bypassPermissions on the wire and would ignore the local UI-only value.\nConfidence: high\nScope-risk: moderate\nDirective: Rebuild apps/hook/dist/index.html after changing plan-review UI because the local plannotator launcher imports the ignored dist bundle at runtime.\nTested: git diff --check; bun run typecheck; bun test; bun run build:review; bun run build:hook; fixed-port hook smoke for /api/settings-status and native-clear /api/approve.\nNot-tested: Manual click-through in Claude Code native plan-accept dialog.
…ction

When user clicks "Approve + Bypass + Clear Context (native)" in plannotator
UI, the hook now spawns a detached background process before exiting 0
(native passthrough). The process injects "1\n" into the CC terminal after
a 600ms delay, auto-selecting "Yes, clear context and bypass permissions"
without a manual keypress.

Detection priority:
  1. tmux ($TMUX_PANE) → tmux send-keys (no accessibility permissions needed)
  2. macOS → osascript iterating {warp, iTerm2, Terminal}
  3. Linux/Windows without tmux → no-op (falls back to manual press)

spawnKeystrokeInjector() detaches via Bun.spawn + .unref() — parent exits
immediately, child fires after delay.

7 unit tests added (265/265 pass). Build clean. Smoke-tested on WarpTerminal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…pawn

Structural cleanup of the keystroke injector without behavior changes:

- Delete 16-line module docblock + 5-line JSDoc (over-commented for 78 lines)
- Inline buildTmuxScript() and buildOsascriptScript() — single-use helpers
- Unify the duplicated Bun.spawn+.unref() into one call at the end: both
  branches now set `script: string | null`, then a single spawn runs if set
- `KNOWN_MACOS_TERMINALS as const` → plain string[] (not a readonly tuple)

Test cleanup:
- Extract setPlatform(v) helper — replaces 5× Object.defineProperty blocks

78→39 lines (implementation), 118→107 lines (tests). 7/7 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Warp ships as Warp.app/Contents/MacOS/stable, so its macOS process name
is "stable" — not "warp". The previous code checked
`exists (application process "warp")` via System Events, which always
returned false on Warp, leaving the keystroke never injected and the
CC plan-accept TUI unattended.

Fix: check `application "Warp" is running` (bundle-name lookup, works
regardless of the binary name) and activate Warp directly before
sending keystrokes. Fall through to process-name search for iTerm2
and Terminal unchanged.

Test: update the osascript assertion to match the new Warp check.
7/7 tests pass.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Constraint: Approved Ralph plan required saved bypassPermissionsClearReminder to nudge /clear without native fresh-thread deferral.\nRejected: Reusing native clear as the default | it can restart or open a fresh thread unexpectedly.\nConfidence: high\nScope-risk: moderate\nDirective: Treat deferToNativeForClear as an explicit native/fresh-thread escape hatch only; do not wire it to saved reminder mode.\nTested: bun test packages/editor/approvalBody.test.ts apps/hook/server/keystrokeInjector.test.ts; git diff --check scoped files; bun run typecheck; bun test; bun run build:hook; architect verification approved.\nNot-tested: Interactive manual browser smoke of Claude Code native dialog selection.
* Install Plannotator skills under Codex home

* Keep shared Plannotator skills in agent scope

* Harden scoped skill migration
* Preserve truthful approval semantics for Claude plan bypass

Thread a clear-context reminder flag through approval decisions, expose a Claude Code-only approval entry that requests bypass mode, and keep the hook response honest by emitting a reminder instead of claiming context was cleared.

Constraint: Claude Code PermissionRequest hooks have no documented clearContext response field and bypassPermissions is only a request when the mode is available.

Rejected: adding a permission-mode enum or undocumented clearContext field | those would misrepresent hook capabilities and broaden the contract.

Confidence: high

Scope-risk: moderate

Directive: Do not claim Plannotator clears context until Claude Code documents a hook field for that behavior; keep reminder copy truthful.

Tested: bun test packages/server apps/hook; bun test packages/editor/wideMode.test.ts packages/ui/hooks/useAgentSettings.test.ts; bun test; bun run build:review; bun run build:hook; bun run typecheck; git diff --check --cached.

Not-tested: Browser warning-dialog replay and interactive Claude Code smoke test.

Co-authored-by: OmX <omx@oh-my-codex.dev>

* Keep approval payloads truthful across Claude Code and Pi

Constraint: Claude Code hooks cannot clear context directly; the new action remains a truthful reminder plus bypass-mode approval.
Rejected: Sending OpenCode agent-switch state for Claude Code | it leaked build (?) UI state and misleading payload fields.
Confidence: high
Scope-risk: narrow
Directive: Keep OpenCode agent switching gated to opencode-origin approval payloads.
Tested: bun run typecheck; bun test; bun run build:review; bun run build:hook
Not-tested: Manual browser click-through of the Claude Code dropdown.

* Expose the clear-context reminder permission default

Constraint: Claude Code hooks can only emit a systemMessage nudge, not clear context directly.

Rejected: Server protocol changes | existing permissionMode plus clearContextNudge wire fields already support the behavior.

Confidence: high

Scope-risk: narrow

Directive: Keep bypassPermissionsClearReminder as a UI/storage-only synthetic mode that decomposes before /api/approve.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd apps/review build && bun run build:hook; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Root bun run typecheck could not run because tsc was not on PATH for the root script.

* Reject invalid persisted permission modes

Constraint: Stored browser values can be stale, corrupt, or from a future Plannotator build.

Rejected: Trusting the storage read with a type assertion | invalid values could flow into UI state and approval request construction.

Confidence: high

Scope-risk: narrow

Directive: Keep PermissionMode storage reads validated against PERMISSION_MODE_OPTIONS when adding or renaming modes.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Full repo typecheck/build, outside this review-fix scope.

* Ensure approvals use the live permission setting

Settings persisted permission mode changes, but App kept the original mode in React state and used that stale value when building approval payloads. Push the Settings change back into App so the selected clear-reminder mode reaches the hook decision.

Constraint: Permission mode storage is cookie-backed while approval payload construction reads App state.\nRejected: Read permission cookies during approval | would couple approval construction to browser storage and duplicate Settings state.\nConfidence: high\nScope-risk: narrow\nDirective: Keep permission-mode writes synchronized with approval state when adding or changing modes.\nTested: bun test packages/editor/approvalBody.test.ts packages/ui/components/ApproveDropdown.test.tsx; bun x tsc --noEmit -p packages/ui/tsconfig.json; bun run build:hook; direct Playwright hook smoke verified bypassPermissionsClearReminder UI and hook payload.\nNot-tested: Live interactive Claude CLI session; direct hook/server simulation covered the wire output.

---------

Co-authored-by: OmX <omx@oh-my-codex.dev>
Thread a clear-context reminder flag through approval decisions, expose a Claude Code-only approval entry that requests bypass mode, and keep the hook response honest by emitting a reminder instead of claiming context was cleared.

Constraint: Claude Code PermissionRequest hooks have no documented clearContext response field and bypassPermissions is only a request when the mode is available.

Rejected: adding a permission-mode enum or undocumented clearContext field | those would misrepresent hook capabilities and broaden the contract.

Confidence: high

Scope-risk: moderate

Directive: Do not claim Plannotator clears context until Claude Code documents a hook field for that behavior; keep reminder copy truthful.

Tested: bun test packages/server apps/hook; bun test packages/editor/wideMode.test.ts packages/ui/hooks/useAgentSettings.test.ts; bun test; bun run build:review; bun run build:hook; bun run typecheck; git diff --check --cached.

Not-tested: Browser warning-dialog replay and interactive Claude Code smoke test.

Co-authored-by: OmX <omx@oh-my-codex.dev>
Constraint: Claude Code hooks cannot clear context directly; the new action remains a truthful reminder plus bypass-mode approval.
Rejected: Sending OpenCode agent-switch state for Claude Code | it leaked build (?) UI state and misleading payload fields.
Confidence: high
Scope-risk: narrow
Directive: Keep OpenCode agent switching gated to opencode-origin approval payloads.
Tested: bun run typecheck; bun test; bun run build:review; bun run build:hook
Not-tested: Manual browser click-through of the Claude Code dropdown.
Route Claude Code plan approvals through explicit bypass payloads, consent-gated native clear-context deferral, and a fallback /clear nudge so selecting the clear-context mode no longer collapses into a silent approval no-op. The active ignored hook bundle was rebuilt locally after this source change.

Constraint: Claude Code hooks cannot directly clear context; native clear requires showClearContextOnPlanAccept and user consent.\nRejected: Treating bypassPermissionsClearReminder as a raw permissionMode | Claude Code only accepts bypassPermissions on the wire and would ignore the local UI-only value.\nConfidence: high\nScope-risk: moderate\nDirective: Rebuild apps/hook/dist/index.html after changing plan-review UI because the local plannotator launcher imports the ignored dist bundle at runtime.\nTested: git diff --check; bun run typecheck; bun test; bun run build:review; bun run build:hook; fixed-port hook smoke for /api/settings-status and native-clear /api/approve.\nNot-tested: Manual click-through in Claude Code native plan-accept dialog.
Constraint: Approved Ralph plan required saved bypassPermissionsClearReminder to nudge /clear without native fresh-thread deferral.\nRejected: Reusing native clear as the default | it can restart or open a fresh thread unexpectedly.\nConfidence: high\nScope-risk: moderate\nDirective: Treat deferToNativeForClear as an explicit native/fresh-thread escape hatch only; do not wire it to saved reminder mode.\nTested: bun test packages/editor/approvalBody.test.ts apps/hook/server/keystrokeInjector.test.ts; git diff --check scoped files; bun run typecheck; bun test; bun run build:hook; architect verification approved.\nNot-tested: Interactive manual browser smoke of Claude Code native dialog selection.
* Preserve truthful approval semantics for Claude plan bypass

Thread a clear-context reminder flag through approval decisions, expose a Claude Code-only approval entry that requests bypass mode, and keep the hook response honest by emitting a reminder instead of claiming context was cleared.

Constraint: Claude Code PermissionRequest hooks have no documented clearContext response field and bypassPermissions is only a request when the mode is available.

Rejected: adding a permission-mode enum or undocumented clearContext field | those would misrepresent hook capabilities and broaden the contract.

Confidence: high

Scope-risk: moderate

Directive: Do not claim Plannotator clears context until Claude Code documents a hook field for that behavior; keep reminder copy truthful.

Tested: bun test packages/server apps/hook; bun test packages/editor/wideMode.test.ts packages/ui/hooks/useAgentSettings.test.ts; bun test; bun run build:review; bun run build:hook; bun run typecheck; git diff --check --cached.

Not-tested: Browser warning-dialog replay and interactive Claude Code smoke test.

Co-authored-by: OmX <omx@oh-my-codex.dev>

* Keep approval payloads truthful across Claude Code and Pi

Constraint: Claude Code hooks cannot clear context directly; the new action remains a truthful reminder plus bypass-mode approval.
Rejected: Sending OpenCode agent-switch state for Claude Code | it leaked build (?) UI state and misleading payload fields.
Confidence: high
Scope-risk: narrow
Directive: Keep OpenCode agent switching gated to opencode-origin approval payloads.
Tested: bun run typecheck; bun test; bun run build:review; bun run build:hook
Not-tested: Manual browser click-through of the Claude Code dropdown.

* Expose the clear-context reminder permission default

Constraint: Claude Code hooks can only emit a systemMessage nudge, not clear context directly.

Rejected: Server protocol changes | existing permissionMode plus clearContextNudge wire fields already support the behavior.

Confidence: high

Scope-risk: narrow

Directive: Keep bypassPermissionsClearReminder as a UI/storage-only synthetic mode that decomposes before /api/approve.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd apps/review build && bun run build:hook; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Root bun run typecheck could not run because tsc was not on PATH for the root script.

* Reject invalid persisted permission modes

Constraint: Stored browser values can be stale, corrupt, or from a future Plannotator build.

Rejected: Trusting the storage read with a type assertion | invalid values could flow into UI state and approval request construction.

Confidence: high

Scope-risk: narrow

Directive: Keep PermissionMode storage reads validated against PERMISSION_MODE_OPTIONS when adding or renaming modes.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Full repo typecheck/build, outside this review-fix scope.

* Ensure approvals use the live permission setting

Settings persisted permission mode changes, but App kept the original mode in React state and used that stale value when building approval payloads. Push the Settings change back into App so the selected clear-reminder mode reaches the hook decision.

Constraint: Permission mode storage is cookie-backed while approval payload construction reads App state.\nRejected: Read permission cookies during approval | would couple approval construction to browser storage and duplicate Settings state.\nConfidence: high\nScope-risk: narrow\nDirective: Keep permission-mode writes synchronized with approval state when adding or changing modes.\nTested: bun test packages/editor/approvalBody.test.ts packages/ui/components/ApproveDropdown.test.tsx; bun x tsc --noEmit -p packages/ui/tsconfig.json; bun run build:hook; direct Playwright hook smoke verified bypassPermissionsClearReminder UI and hook payload.\nNot-tested: Live interactive Claude CLI session; direct hook/server simulation covered the wire output.

---------

Co-authored-by: OmX <omx@oh-my-codex.dev>
* feat(review): add jj support for local diffs

* feat(review): add jj review workflows

* fix(review): tighten jj diff defaults

* test(review): add jj manual sandbox

* fix(review): share jj agent diff prompts

* fix(review): quote jj agent revsets

* feat(review): share jj vcs handling with pi

* fix(review): tighten jj bookmark and pi pr handling

* fix(review): tighten jj defaults and detection

* fix(review): harden jj diff and vcs detection

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
…es (backnotprop#689)

PFM reminder & improvement hook support across Claude Code, OpenCode, and Pi.

- Add opt-in PFM reminder (pfmReminder config flag) injected on EnterPlanMode
- Wire composeImproveContext() into all three runtimes
- Fix OpenCode system.transform array reference bug (pushes were going to dead array)
- Fix install scripts silently stripping PreToolUse/EnterPlanMode hook entry
- Isolated Pi sandbox testing (--no-extensions -e)
…backnotprop#692)

Code file line range references with hover preview + Graphviz improvements.

Line ranges: `file.ts:42` and `file.ts:10-20` are fully supported with
syntax-highlighted hover preview popover (150ms delay, GitHub-style
persistence). New parseCodePath() utility, server-side line suffix
stripping on both Bun and Pi servers, ambiguous picker preserves line
suffix. useCodeFilePopout moved to hooks/pfm/.

Graphviz: responsive container height from SVG aspect ratio, white
background polygon removed, default colors (black, lightgrey) replaced
with theme tokens via SVG post-processing. User-specified colors
preserved.
* Preserve truthful approval semantics for Claude plan bypass

Thread a clear-context reminder flag through approval decisions, expose a Claude Code-only approval entry that requests bypass mode, and keep the hook response honest by emitting a reminder instead of claiming context was cleared.

Constraint: Claude Code PermissionRequest hooks have no documented clearContext response field and bypassPermissions is only a request when the mode is available.

Rejected: adding a permission-mode enum or undocumented clearContext field | those would misrepresent hook capabilities and broaden the contract.

Confidence: high

Scope-risk: moderate

Directive: Do not claim Plannotator clears context until Claude Code documents a hook field for that behavior; keep reminder copy truthful.

Tested: bun test packages/server apps/hook; bun test packages/editor/wideMode.test.ts packages/ui/hooks/useAgentSettings.test.ts; bun test; bun run build:review; bun run build:hook; bun run typecheck; git diff --check --cached.

Not-tested: Browser warning-dialog replay and interactive Claude Code smoke test.

Co-authored-by: OmX <omx@oh-my-codex.dev>

* Keep approval payloads truthful across Claude Code and Pi

Constraint: Claude Code hooks cannot clear context directly; the new action remains a truthful reminder plus bypass-mode approval.
Rejected: Sending OpenCode agent-switch state for Claude Code | it leaked build (?) UI state and misleading payload fields.
Confidence: high
Scope-risk: narrow
Directive: Keep OpenCode agent switching gated to opencode-origin approval payloads.
Tested: bun run typecheck; bun test; bun run build:review; bun run build:hook
Not-tested: Manual browser click-through of the Claude Code dropdown.

* Expose the clear-context reminder permission default

Constraint: Claude Code hooks can only emit a systemMessage nudge, not clear context directly.

Rejected: Server protocol changes | existing permissionMode plus clearContextNudge wire fields already support the behavior.

Confidence: high

Scope-risk: narrow

Directive: Keep bypassPermissionsClearReminder as a UI/storage-only synthetic mode that decomposes before /api/approve.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd apps/review build && bun run build:hook; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Root bun run typecheck could not run because tsc was not on PATH for the root script.

* Reject invalid persisted permission modes

Constraint: Stored browser values can be stale, corrupt, or from a future Plannotator build.

Rejected: Trusting the storage read with a type assertion | invalid values could flow into UI state and approval request construction.

Confidence: high

Scope-risk: narrow

Directive: Keep PermissionMode storage reads validated against PERMISSION_MODE_OPTIONS when adding or renaming modes.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Full repo typecheck/build, outside this review-fix scope.

* Ensure approvals use the live permission setting

Settings persisted permission mode changes, but App kept the original mode in React state and used that stale value when building approval payloads. Push the Settings change back into App so the selected clear-reminder mode reaches the hook decision.

Constraint: Permission mode storage is cookie-backed while approval payload construction reads App state.\nRejected: Read permission cookies during approval | would couple approval construction to browser storage and duplicate Settings state.\nConfidence: high\nScope-risk: narrow\nDirective: Keep permission-mode writes synchronized with approval state when adding or changing modes.\nTested: bun test packages/editor/approvalBody.test.ts packages/ui/components/ApproveDropdown.test.tsx; bun x tsc --noEmit -p packages/ui/tsconfig.json; bun run build:hook; direct Playwright hook smoke verified bypassPermissionsClearReminder UI and hook payload.\nNot-tested: Live interactive Claude CLI session; direct hook/server simulation covered the wire output.

---------

Co-authored-by: OmX <omx@oh-my-codex.dev>
…es (backnotprop#689)

PFM reminder & improvement hook support across Claude Code, OpenCode, and Pi.

- Add opt-in PFM reminder (pfmReminder config flag) injected on EnterPlanMode
- Wire composeImproveContext() into all three runtimes
- Fix OpenCode system.transform array reference bug (pushes were going to dead array)
- Fix install scripts silently stripping PreToolUse/EnterPlanMode hook entry
- Isolated Pi sandbox testing (--no-extensions -e)
backnotprop and others added 8 commits May 14, 2026 16:14
…backnotprop#692)

Code file line range references with hover preview + Graphviz improvements.

Line ranges: `file.ts:42` and `file.ts:10-20` are fully supported with
syntax-highlighted hover preview popover (150ms delay, GitHub-style
persistence). New parseCodePath() utility, server-side line suffix
stripping on both Bun and Pi servers, ambiguous picker preserves line
suffix. useCodeFilePopout moved to hooks/pfm/.

Graphviz: responsive container height from SVG aspect ratio, white
background polygon removed, default colors (black, lightgrey) replaced
with theme tokens via SVG post-processing. User-specified colors
preserved.
…rop#687)

Add --render-html flag to plannotator annotate that renders HTML files
as-is in an iframe instead of converting to markdown. Includes annotation
support via postMessage bridge, sharing via paste service, and theme
inheritance from Plannotator's 30+ themes.

New skill: plannotator-visual-explainer — wraps nicobailon/visual-explainer
with Plannotator theme tokens, extended patterns (timelines, SVG diagrams,
code blocks, risk tables, Pierre diffs via CDN), and plan/PR-specific guidance.

All three servers (Bun, Pi, OpenCode) support the new flag.
…tprop#707)

* feat(ui): show copyable file path and guidance in Hooks settings tab

Always return the improvement hook file path from /api/hooks/status
(actual path when present, expected path when absent) so the UI can
display it in both states. Add CopyPathButton with tilde-shortened
display and full-path clipboard copy. When active, guide users to
edit directly or regenerate via /plannotator-compound. When absent,
show expected path and both creation options (auto-generate or manual).

* fix(ui): anchor displayPath on .plannotator instead of guessing homedir

The regex assumed home directories are always two segments deep
(/Users/x), which breaks for /root on Linux — it would capture
/root/.plannotator as the home prefix and display ~/hooks/... instead
of ~/.plannotator/hooks/..., leading users to create the file in the
wrong location.
Thread a clear-context reminder flag through approval decisions, expose a Claude Code-only approval entry that requests bypass mode, and keep the hook response honest by emitting a reminder instead of claiming context was cleared.

Constraint: Claude Code PermissionRequest hooks have no documented clearContext response field and bypassPermissions is only a request when the mode is available.

Rejected: adding a permission-mode enum or undocumented clearContext field | those would misrepresent hook capabilities and broaden the contract.

Confidence: high

Scope-risk: moderate

Directive: Do not claim Plannotator clears context until Claude Code documents a hook field for that behavior; keep reminder copy truthful.

Tested: bun test packages/server apps/hook; bun test packages/editor/wideMode.test.ts packages/ui/hooks/useAgentSettings.test.ts; bun test; bun run build:review; bun run build:hook; bun run typecheck; git diff --check --cached.

Not-tested: Browser warning-dialog replay and interactive Claude Code smoke test.

Co-authored-by: OmX <omx@oh-my-codex.dev>
Constraint: Claude Code hooks cannot clear context directly; the new action remains a truthful reminder plus bypass-mode approval.
Rejected: Sending OpenCode agent-switch state for Claude Code | it leaked build (?) UI state and misleading payload fields.
Confidence: high
Scope-risk: narrow
Directive: Keep OpenCode agent switching gated to opencode-origin approval payloads.
Tested: bun run typecheck; bun test; bun run build:review; bun run build:hook
Not-tested: Manual browser click-through of the Claude Code dropdown.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants